package castledefense.util;

import castledefense.game.screens.MainGameScreen;
import castledefense.logic.Map;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;

public class MeshGenerator {
	/**
	 * @param x
	 *            bottom left X
	 * @param y
	 *            bottom left Y
	 * @param width
	 * @param height
	 * @param color
	 * @return
	 */
	public static Mesh newRectangle(int x, int y, int width, int height,
			Color color) {
		return newRectangle(x, y, width, height, color, color, color, color);
	}

	/**
	 * @param x
	 *            bottom left X
	 * @param y
	 *            bottom left Y
	 * @param width
	 * @param height
	 * @param bl
	 *            bottom left color
	 * @param br
	 *            bottom right color
	 * @param tr
	 *            top right color
	 * @param tl
	 *            top left color
	 * @return
	 */
	public static Mesh newRectangle(int x, int y, int width, int height,
			Color bl, Color br, Color tr, Color tl) {
		return newQuad(x, y, bl, x + width, y, br, x + width, y + height, tr,
				x, y + height, tl);
	}

	/**
	 * @param blX
	 *            bottom left X
	 * @param blY
	 *            bottom left Y
	 * @param brX
	 *            bottom right X
	 * @param brY
	 *            bottom right Y
	 * @param trX
	 *            top right X
	 * @param trY
	 *            top right Y
	 * @param tlX
	 *            top left X
	 * @param tlY
	 *            top left Y
	 * @param color
	 * @return
	 */
	public static Mesh newQuad(int blX, int blY, int brX, int brY, int trX,
			int trY, int tlX, int tlY, Color color) {
		return newQuad(blX, blY, color, brX, brY, color, trX, trY, color, tlX,
				tlY, color);
	}

	/**
	 * @param blX
	 *            bottom left X
	 * @param blY
	 *            bottom left Y
	 * @param bl
	 *            bottom left color
	 * @param brX
	 *            bottom right X
	 * @param brY
	 *            bottom right Y
	 * @param br
	 *            bottom right color
	 * @param trX
	 *            top right X
	 * @param trY
	 *            top right Y
	 * @param tr
	 *            top right color
	 * @param tlX
	 *            top left X
	 * @param tlY
	 *            top left Y
	 * @param tl
	 *            top left color
	 * @return
	 */
	public static Mesh newQuad(int blX, int blY, Color bl, int brX, int brY,
			Color br, int trX, int trY, Color tr, int tlX, int tlY, Color tl) {
		return newPolygon(new int[] { blX, brX, trX, tlX }, new int[] { blY,
				brY, trY, tlY }, 4, new Color[] { bl, br, tr, tl });
	}

	public static Mesh newPolygon(int x[], int y[], int length, Color color) {
		Color colors[] = new Color[length];
		for (int a = 0; a < length; a++)
			colors[a] = color;
		return newPolygon(x, y, length, colors);
	}

	public static Mesh newPolygon(int x[], int y[], int length, Color colors[]) {
		float[] x2 = new float[length];
		float[] y2 = new float[length];
		for (int i = 0; i < length; i++) {
			x2[i] = x[i];
			y2[i] = y[i];
		}
		return newPolygonFloat(x2, y2, length, colors);
	}

	public static Mesh newPolygonFloat(float x[], float y[], int length,
			Color colors[]) {
		if (x.length < length)
			throw new IllegalArgumentException("Too little X vertices.");
		if (y.length < length)
			throw new IllegalArgumentException("Too little Y vertices.");
		if (colors.length < length)
			throw new IllegalArgumentException("Too little colors.");

		Mesh mesh = new Mesh(true, length, length, new VertexAttribute(
				Usage.Position, 3, "quad_positions"), new VertexAttribute(
				Usage.ColorPacked, 4, "quad_colors"));

		float vertices[] = new float[length * 4];
		short indices[] = new short[length];
		for (int a = 0; a < length; a++) {
			vertices[a * 4] = x[a];
			vertices[a * 4 + 1] = y[a];
			vertices[a * 4 + 2] = 0;
			vertices[a * 4 + 3] = colors[a].toFloatBits();

			indices[a] = (short) a;
		}

		mesh.setVertices(vertices);
		mesh.setIndices(indices);

		return mesh;
	}

	final static short MAX = 256;
	static float verticesPOOL[] = new float[MAX * 2];

	/** MAX VERTICE SIZE 256!! */
	public static Mesh newPolygonFast(float x[], float y[], int length) {
		if (length > MAX) {
			verticesPOOL = new float[length * 2];
		}
		Mesh mesh = new Mesh(true, length, length, new VertexAttribute(
				Usage.Position, 2, "line_positions"));
		short indices[] = new short[length];
		for (int a = 0; a < length; a++) {
			verticesPOOL[a * 2] = x[a];
			verticesPOOL[a * 2 + 1] = y[a];
			indices[a] = (short) a;
		}
		mesh.setVertices(verticesPOOL, 0, length * 2);
		mesh.setIndices(indices, 0, length);

		return mesh;
	}

	public static Mesh newCircle(int x, int y, int radius, Color color) {
		return newOval(x, y, radius, radius, color);
	}

	public static int numPoints = 36;

	/**
	 * @param x
	 *            bottom left X
	 * @param y
	 *            bottom left Y
	 * @param width
	 * @param height
	 * @param color
	 * @return
	 */
	public static Mesh newOval(int x, int y, int width, int height, Color color) {
		Mesh mesh = new Mesh(true, numPoints, numPoints, new VertexAttribute(
				Usage.Position, 3, "oval_positions"), new VertexAttribute(
				Usage.ColorPacked, 4, "oval_colors"));
		float vertices[] = new float[numPoints * 4];
		short indices[] = new short[numPoints];
		int halfWidth = width / 2;
		int halfHeight = height / 2;
		for (int a = 0; a < numPoints; a++) {
			float angle = a * (360.0f / numPoints);

			vertices[a * 4] = FastMath.cosDeg(angle) * halfWidth
					+ (x + halfWidth);
			vertices[a * 4 + 1] = FastMath.sinDeg(angle) * halfHeight
					+ (y + halfHeight);
			vertices[a * 4 + 2] = 0;
			vertices[a * 4 + 3] = color.toFloatBits();

			indices[a] = (short) a;
		}

		mesh.setVertices(vertices);
		mesh.setIndices(indices);

		return mesh;
	}

	public static Mesh MapGrid() {
		final int maxX = MainGameScreen.mapSizeX;
		final int maxY = MainGameScreen.mapSizeX;
		int n = 0;
		final float[] x = new float[(maxX - 1) * 2 + (maxY - 1) * 2];
		final float[] y = new float[(maxX - 1) * 2 + (maxY - 1) * 2];

		final int size = Map.cellWidth;
		for (int i = 0; i < maxX - 1; i++) {
			x[i * 2] = i * size + size;
			x[i * 2 + 1] = i * size + size;

			y[i * 2] = 0;
			y[i * 2 + 1] = maxX * size;

			n += 2;
		}
		final int tmp = n;
		for (int i = 0; i < maxX - 1; i++) {
			x[tmp + i * 2] = 0;
			x[tmp + i * 2 + 1] = maxX * size;
			y[tmp + i * 2] = i * size + size;
			y[tmp + i * 2 + 1] = i * size + size;
			n += 2;
		}
		return MeshGenerator.newPolygonFast(x, y, n);
	}
}
